{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import math\n",
    "import matplotlib.pyplot as plt\n",
    "import random\n",
    "from tqdm import tqdm"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [],
   "source": [
    "city = [[0.4, 0.2439], [0.1707, 0.2293], [0.5171, 0.4439], [0.1463, 0.2293], [0.761, 0.9414], [0.8732, 0.6878], [0.8488, 0.6683], [0.6195, 0.6536], [0.5219, 0.3609], [0.2536, 0.2634]]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {},
   "outputs": [],
   "source": [
    "def visualizer(path):\n",
    "    x = [p[0] for p in city]\n",
    "    y = [p[1] for p in city]\n",
    "    plt.plot(x, y, 'o')\n",
    "    city_reorder = [city[i] for i in path]\n",
    "    x_re = [p[0] for p in city_reorder]\n",
    "    y_re = [p[1] for p in city_reorder]\n",
    "    x_re.append(x_re[0])\n",
    "    y_re.append(y_re[0])\n",
    "    plt.plot(x_re, y_re, linewidth=1, color='red')\n",
    "    plt.savefig(\"path.png\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [],
   "source": [
    "distances = [[-1 for j in range(10)] for i in range(10)]\n",
    "\n",
    "def computePointDistance(x, y):\n",
    "    if distances[x][y] >= 0:\n",
    "        return distances[x][y]\n",
    "    else:\n",
    "        distances[x][y] = math.sqrt((city[x][0] - city[y][0]) ** 2 + (city[x][1] - city[y][1]) ** 2)\n",
    "    return distances[x][y]\n",
    "\n",
    "def computePathDistance(path):\n",
    "    totalDistance = 0.0\n",
    "    for i in range(10):\n",
    "        if i == 9:\n",
    "            distance = computePointDistance(path[9], path[0])\n",
    "        else:\n",
    "            distance = computePointDistance(path[i], path[i+1])\n",
    "        totalDistance += distance\n",
    "    return totalDistance\n",
    "\n",
    "def getExchangeOfTwoPath(source, target):\n",
    "    exchange = []\n",
    "    s = np.array(source)\n",
    "    t = np.array(target)\n",
    "    for i in range(10):\n",
    "        target_fig = t[i]\n",
    "        for j in range(10):\n",
    "            if s[j] == target_fig:\n",
    "                # tmp = s[j]\n",
    "                # s[j] = s[i]\n",
    "                # s[i] = tmp\n",
    "                exchange.append([i, j])\n",
    "                break\n",
    "    return exchange\n",
    "\n",
    "def initRandomPath():\n",
    "    p = [i for i in range(10)]\n",
    "    random.shuffle(p)\n",
    "    return p\n",
    "\n",
    "def initRandomExchange():\n",
    "    exchange = []\n",
    "    for i in range(10):\n",
    "        rd1 = np.random.randint(0, 10)\n",
    "        rd2 = np.random.randint(0, 10)\n",
    "        while(rd1 == rd2):\n",
    "            rd2 = np.random.randint(0, 10)\n",
    "        exchange.append([rd1, rd2])\n",
    "    return exchange\n",
    "\n",
    "def selectRandomly(exchange, paritition):\n",
    "    n_select = int(10 * paritition)\n",
    "    choices = [i for i in range(10)]\n",
    "    s = random.sample(choices, n_select)\n",
    "    e = [exchange[s[i]] for i in range(n_select)]\n",
    "    return e\n",
    "\n",
    "\n",
    "def getNewpath(path, exchange):\n",
    "    p = path.copy()\n",
    "    for i, j in exchange:\n",
    "        tmp = p[i]\n",
    "        p[i] = p[j]\n",
    "        p[j] = tmp\n",
    "    return p\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [],
   "source": [
    "def PSO(n_epochs = 200, m = 100, alpha = 0.3, beta = 0.3):\n",
    "    population = []\n",
    "    velocity = []\n",
    "    distances = []\n",
    "    personal_best_path =[]\n",
    "    all_best_path = None\n",
    "    all_best_distance = 1000.0\n",
    "    all_best_distances = []\n",
    "    for i in range(m):\n",
    "        population.append(initRandomPath())\n",
    "        velocity.append(initRandomExchange())\n",
    "        distances.append(computePathDistance(population[i]))\n",
    "        personal_best_path.append(population[i])\n",
    "    idx = np.argmin(distances)\n",
    "    all_best_path = population[idx]\n",
    "    all_best_distances.append(computePathDistance(all_best_path))\n",
    "    all_best_distance = computePathDistance(all_best_path)\n",
    "\n",
    "    for i in tqdm(range(n_epochs)):\n",
    "        for j in range(m):\n",
    "            personal_better = getExchangeOfTwoPath(population[j], personal_best_path[j])\n",
    "            all_better = getExchangeOfTwoPath(population[j], all_best_path)\n",
    "            personal_better = selectRandomly(personal_better, alpha)\n",
    "            all_better = selectRandomly(all_better, beta)\n",
    "            velocity[j].extend(personal_better)\n",
    "            velocity[j].extend(all_better)\n",
    "            population[j] = getNewpath(population[j], velocity[j])\n",
    "            newDistance = computePathDistance(population[j])\n",
    "            if newDistance < distances[j]:\n",
    "                personal_best_path[j] = population[j]\n",
    "            distances[j] = newDistance\n",
    "        idx = np.argmin(distances)\n",
    "        if all_best_distance > distances[idx]:\n",
    "            all_best_path = population[idx]\n",
    "            all_best_distance = distances[idx]\n",
    "        all_best_distances.append(computePathDistance(all_best_path))\n",
    "    return all_best_distances, all_best_path\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|██████████| 200/200 [00:01<00:00, 163.24it/s]\n"
     ]
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2.1664564401079174\n",
      "2.1664564401079174\n"
     ]
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "\n",
    "# 重复100次寻找最优参数\n",
    "# total = 0.0\n",
    "# for i in range(100):\n",
    "#     all_best_distance, all_best_path = PSO(alpha = 0.5, beta = 0.5)\n",
    "#     total += all_best_distance[-1]\n",
    "#     # print(all_best_distance[-1])\n",
    "# print(total / 100)\n",
    "\n",
    "# 找到最优参数后进行测试\n",
    "all_best_distance, all_best_path = PSO(alpha = 0.1, beta = 0.1)\n",
    "plt.plot(all_best_distance)\n",
    "plt.xlabel(\"Epoch\")\n",
    "plt.ylabel(\"Best Distance\")\n",
    "plt.show()\n",
    "print(computePathDistance(all_best_path))\n",
    "visualizer(all_best_path)\n",
    "print(all_best_distance[-1])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "interpreter": {
   "hash": "79c38198e3a853eeea51b70a0ae21c719ed1444592bdd4a45c4de9d24fbfec7c"
  },
  "kernelspec": {
   "display_name": "Python 3.7.7 64-bit",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.7"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
